<?php


namespace app\services\utils;


use think\facade\Cache;

class LockService
{
    private $redis;
    private $lockKey;
    private $expiration;
    private $maxRetries;

    /**
     * LockService constructor.
     * @param $lockKey
     * @param $expiration
     * @param $maxRetries
     */
    public function __construct($lockKey, $expiration = 10, $maxRetries = 3)
    {
        $this->redis = Cache::store('redis')->handler();
        // redis键
        $this->lockKey = $lockKey;
        // 过期时间
        $this->expiration = $expiration;
        // 重试次数
        $this->maxRetries = $maxRetries;
    }

    public function acquireLockWithoutRetry($identifier)
    {
        $result = $this->redis->set($this->lockKey, $identifier, ['NX', 'EX' => $this->expiration]);
        return $result ? true : false;
    }

    public function acquireLockWithRetry($identifier)
    {
        $retryCount = 0;
        while ($retryCount < $this->maxRetries) {
            $result = $this->redis->set($this->lockKey, $identifier, ['NX', 'EX' => $this->expiration]);
            if ($result) {
                return true;
            }

            usleep(100000); // 100毫秒
            $retryCount++;
        }

        return false;
    }

    public function releaseLock($identifier)
    {
        $script = "
            if redis.call('get', KEYS[1]) == ARGV[1] then
                return redis.call('del', KEYS[1])
            else
                return 0
            end
        ";

        $result = $this->redis->eval($script, [$this->lockKey, $identifier], 1);
        return $result ? true : false;
    }
}